#ifndef __LICH_NODE_H__
#define __LICH_NODE_H__

#include "sysy_lib.h"
#include "etcd.h"
#include "cluster.h"

typedef enum {
        NODE_STAT_NONE,
        NODE_STAT_NORMAL,
        NODE_STAT_META,
        NODE_STAT_ADMIN,
} node_status_t;

typedef enum {
        NODE_OP_NONE,

        NODE_OP_ADMIN_CHECK, /*add a node as normal by admin*/
        NODE_OP_NONE_SETADMIN, /*set a node as master by admin*/
        NODE_OP_NONE_GETINFO,
        NODE_OP_NONE_NETINFO,
        NODE_OP_NONE_CASTOFF,
        NODE_OP_NONE_POOLDROP,
        NODE_OP_NONE_BALANCE,

        NODE_OP_NORMAL_SETMETA, /*set a normal meta by admin*/

        NODE_OP_META_DROP, /*set a meta as normal by admin*/
        NODE_OP_META_ADDPEER, /*notify metas a new meta added by admin*/
        NODE_OP_META_DROPPEER,/*notify metas a meta dropped by admin*/
        NODE_OP_META_PUSH,/*push new quorum to metas*/

        NODE_OP_ADMIN_JOIN, /*notify admin to add a node by admin*/
        NODE_OP_ADMIN_SETMETA, /*notify admin to set a normal by admin*/
        NODE_OP_ADMIN_DROPMETA,  /*notify admin to drop a meta by admin*/
        NODE_OP_ADMIN_SYNCED,  /*check peer sync status*/
        NODE_OP_ADMIN_GETLIST_OPEN,
        NODE_OP_ADMIN_GETLIST,
        NODE_OP_ADMIN_GETLIST_CLOSE,
        NODE_OP_ADMIN_GETHOST,
        NODE_OP_ADMIN_COUNT,
        NODE_OP_ADMIN_DROPNODE,
        
        NODE_OP_SET_VARIABLE,
        NODE_OP_FETCH_VARIABLE,

        NODE_OP_MAX,
} node_op_t;

inline static const char *node_status(node_status_t status)
{
        static char *node_status[] = {"none", "normal", "meta", "admin"};

        if (status > NODE_STAT_ADMIN) {
                int __i = 0, __j __attribute((unused));
                __j = 1 / __i;
        }

        return node_status[status];
}

typedef int (*node_op_handler)(void *_rep, uint32_t *_replen, const void *_req);

typedef struct {
        char home[MAX_PATH_LEN];
        char name[MAX_NAME_LEN];
        char clustername[MAX_NAME_LEN];
        char status[MAX_NAME_LEN];
        char admin[MAX_NAME_LEN];
        int inited;
} node_t;

typedef struct {
        uint32_t uptime;
        uint64_t seq;
        sy_rwlock_t lock;
} admin_t;

extern node_t __node__;

static inline int __is_none()
{
        if (strcmp(__node__.status, NODE_STATUS_NONE)) {
                return 0;
        } else
                return 1;
}

int node_none_getinfo(nodeinfo_t *info, const char *name);
int node_none_netinfo(ynet_net_info_t *_info, const char *name);

int node_admin_writeable(int *_count);

int node_stat(nodestat_t *stat, nodedfree_t *dfree);
int node_ready(void);
void node_set_deleting(int deleting);
int node_get_deleting(void);

/*new pattern*/
int node_srv_init(const char *home);
int node_srv_heartbeat(int force);
int node_srv_getinfo(nodeinfo_t *info, char *buf);
int node_srv_admin_getnid(nid_t *nid);
int node_srv_admin_version(uint32_t *version);
int node_srv_admin_newid(chkid_t *chkid);
int node_srv_admin_join(const char *name);
int node_srv_admin_check();

int node_srv_none_castoff(int idx);
int node_srv_none_pooldrop(const char *pool);

int node_admin_start(etcd_lock_t *lock, const char *master);
int node_normal_start(etcd_lock_t *lock, const char *master, const int *idx);

/*from node_rpc.c*/
int node_rpc_init(void);

int node_rpc_admin_join(const char *master, const char *name);
int node_rpc_admin_dropnode(const char *admin, const char *name);
int node_rpc_admin_gethost(const char *admin, const nid_t *nid, char *host);
int node_rpc_admin_getlist_open(const char *admin, const char *uuid);
int node_rpc_admin_getlist(const char *admin, char *buf, int *len, const char *uuid, uint64_t offset);
int node_rpc_admin_getlist_close(const char *admin, const char *uuid);
int node_rpc_admin_count(const char *admin, int *count);

int node_rpc_admin_setmeta(const char *admin, const char *name, int force);
int node_rpc_admin_dropmeta(const char *admin, const char *name, int force);

int node_rpc_admin_synced(const char *admin, const char *name, int *synced);
int node_rpc_admin_commit(const char *req, int reqlen, const char *rep,
                          int replen, job_t *job, int peer_count);
int node_rpc_admin_check(const char *admin, int *_ismaster);

int node_rpc_none_getinfo(char *info, int *buflen, const char *name, int timeout);
int node_rpc_none_castoff(const char *name, int idx);
int node_rpc_none_pooldrop(const char *name, const char *pool);

int node_rpc_set_variable(const char *name, const char *key, const char *value);
int node_rpc_fetch_variable(const char *name, const char *key, char *value);

/*from node.c*/
int node_start(void);
int node_setstatus(const char *name, const char *from, const char *to);

int node_getlist_open(const char *admin, const char *uuid);
int node_getlist(const char *admin, char *buf, int *len, const char *uuid, uint64_t offset);
int node_getlist_close(const char *admin, const char *uuid);

int node_count(const char *admin, int *count);

#endif
